import math
import random

from panda3d.core import VBase3, Vec3
import database.units


class UnitNetManager():

    def __init__(self, player):
        self.units = []
        self.saves = []
        self.warpzones = []
        self.player = player
        return

    def update(self, dt):
        for u in self.units:
            u.update(dt, self.player.session.towermanager.towers)
        self.resolve_collisions(dt)
        for u in self.units:
            u.towercollisions(self.player.session.towermanager.towers)

    def place_unit(self, name, pos):
        print "now placing"
        unit = database.units.get_unit_data(name)
        if self._placementcheck(unit, Vec3(pos[0], pos[1], 0)):
            self.build_unit(name, pos)
            self.player.money -= unit.cost
            return True
        return False

    def place_warpzone(self, pos):
        data = database.units.get_unit_data("warpzone")
        if self._placementcheck(data, Vec3(pos[0], pos[1], 0)):
            unit = database.units.create_web_unit("warpzone")
            pos = Vec3(pos[0], pos[1], 0)
            unit.pos = pos
            self.warpzones.append(unit)
            self.player.money -= data.cost
            return True
        return False

    def build_unit(self, name, pos):
        unit = database.units.create_web_unit(name)
        pos = Vec3(pos[0], pos[1], 0)
        unit.pos = pos
        unit.basepos = Vec3(pos.x, pos.y, 0)
        unit.basehp = unit.hp
        unit.set_destination(0, 0)
        unit.manager = self
        self.units.append(unit)


    def upgrade(self, ind, up):
        print "upgrading"
        old = self.units[ind]
        unit = database.units.get_unit_data(old.upgrades[up])
        #amount = unit.amount - 1
        if self.player.money >= unit.cost:
            self.player.money -= unit.cost
            self.build_unit(unit.name, (old.pos.x, old.pos.y, 0))
            #for i in range(amount):
            #    self.player.build_tower(unit.name, (old.pos.x + random.random() * 0.1, old.pos.y + random.random() * 0.1))
            self.units.remove(old)
            #self.resolve_collissions(1)
            return True
        return False

    def destiny(self, unit, destiny):
        if destiny == 1:
            self.player.money += unit.worth
            self.player.session.remove_life()
            self.player.update_money()
        else:
            self.player.session.defender.money += unit.worth
            self.player.session.defender.update_money()
        self.player.session.destroy_unit(self.units.index(unit))
        self.units.remove(unit)
        del unit

    def select(self, pos):
        for t in self.units:
            if VBase3.length(Vec3(pos[0],pos[1],0) - t.pos) < t.radius:
                return t
        return None

    def get_placed(self):
        return self.units

    def save_units(self):
        self.saves = []
        for u in self.units:
            data = database.units.get_unit_data(u.name)
            data.pos = (u.pos.x, u.pos.y)
            self.saves.append(data)

    def restore_units(self):
        self.units = []
        for s in self.saves:
            self.build_unit(s.name, s.pos)

    def _placementcheck(self, unit, pos):
        if VBase3.length(pos) < 15 or VBase3.length(pos) > 26:
            return False
        else:
            for u in self.units:
                if u.radius+unit.radius > VBase3.length(u.pos-pos):
                    return False
        if self.player.money < unit.cost:
            return False
        if unit.name != "warpzone":
            if len(self.warpzones) == 0:
                return False
            inthezone = False
            for w in self.warpzones:
                dis = w.pos - pos
                if VBase3.length(dis) <= w.speed:
                    inthezone = True
            if not inthezone:
                return False
        return True

    def resolve_collisions(self, dt):
        col = False
        for unit in self.units:
            force = Vec3(0, 0, 0)
            factor = 0
            collisions = 0
            for i in range(self.units.index(unit)+1, len(self.units)):
                if unit != self.units[i]:
                    dis = unit.pos - self.units[i].pos
                    quadrad = (unit.radius + self.units[i].radius)*(unit.radius + self.units[i].radius)
                    quaddis = dis.x*dis.x+dis.y*dis.y
                    if quaddis < quadrad:
                        #factor += (quadrad - quaddis)/quadrad
                        factor += (unit.radius + self.units[i].radius) - VBase3.length(dis)
                        force += dis
                        collisions += 1
            if collisions > 0:
                VBase3.normalize(force)
                factor /= collisions
                factor *= dt*10
                #factor = math.sqrt(factor)
                unit.pos += Vec3(force.x * factor, force.y * factor, 0)
                if not col:
                    col = True
        return col

    def normalize(self, vec2):
        leng = self.length(vec2)
        return (vec2[0]/leng, vec2[1]/leng)

    def length(self, vec2):
        return math.sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1])